package tfts

type latency interface {
	react(*action) bool
	String() string
}

type callable struct {
	name     string
	Heal     string // 技能治疗，支持表达式如最大生命值 10*hp => 10%最大生命值
	Shield   string // 护盾，支持表达式如最大生命值
	duration int    // 护盾持续时间
	Grow     string // 最大生命值成长，支持表达式如最大生命值
	buff     *buffMeta
	mana     int
	swing    int // 施法前摇，单位100ms
	calls    []func(*Fight)
}

type action struct {
	latency
	callable
	attrMeta
	*Hook
	fight *Fight
	next  *action
	count int
	cond  []func(*Fight) bool
}

type onceR struct {
	num    int
	target int
}

type rangeR struct {
	left  int // 不包含左边界
	right int // 包含右边界
}

type repeatR struct {
	current   int
	threshold int
}

type stackR struct {
	times   int // 触发多少次叠加一层
	current int
	stack   int
	max     int
	reset   bool // 是否在最大层时重置
}

func NewAction(f *Fight, attrs ...*attrMeta) *action {
	meta := &attrMeta{factor: 100}
	for _, attr := range attrs {
		meta.Add(attr)
	}
	res := &action{
		attrMeta: *meta,
	}
	return res.attach(f)
}

func min(x any, y float64) float64 {
	z := 0.0
	switch x.(type) {
	case int:
		z = float64(x.(int))
	case float64:
	default:
		panic("damage type error")
	}
	if z < y {
		return z
	}
	return y
}

func (o *onceR) react(a *action) bool {
	o.num++
	if o.num != o.target {
		return false
	}
	a.factor = 100 // 使得属性值生效
	return true
}

func (o *onceR) String() string {
	return "一次性"
}

func (r *rangeR) react(a *action) bool {
	return false
}

func (r *rangeR) String() string {
	return "时间段"
}

func (r *repeatR) react(_ *action) bool {
	r.current++
	return r.current%r.threshold == 0
}

func (r *repeatR) String() string {
	return "重复"
}

func (s *stackR) react(a *action) bool {
	s.current++
	if s.current%s.times != 0 {
		return false
	}
	if s.stack == s.max && s.max > 0 {
		return false
	}
	if s.reset && s.stack == s.max {
		s.stack = 0
	}
	if s.stack < s.max || s.max <= 0 {
		s.stack++
	}
	a.factor = s.stack * 100
	if s.stack == s.max && s.max > 0 {
		return true
	}
	if s.max == -1 {
		return true
	}
	return false
}

func (s *stackR) String() string {
	return "可叠加"
}

func (c *callable) defence(champ *Fight) *Shield {
	return champ.Recover(c)
}

func (a *action) handle(e Event) {
	if a.Hook == nil {
		return
	}
	if !a.match(e) {
		return
	}
	if a.latency == nil || a.react(a) {
		if a.buff != nil {
			a.buff.attach(a.fight)
		}
		a.defence(a.fight)
		a.count++
		for _, foo := range a.calls {
			foo(a.fight)
			traceLog("%4.1f秒:[%s]触发%d次\n", a.fight.current(), a.name, a.count)
		}
	}
}

func (a *action) Condition(cond func(*Fight) bool) *action {
	a.cond = append(a.cond, cond)
	return a
}

func (a *action) valid() bool {
	for _, c := range a.cond {
		if !c(a.fight) {
			return false
		}
	}
	return true
}

func (a *action) attach(f *Fight) *action {
	a.fight = f
	f.attrs = append(f.attrs, a)
	f.handlers = append(f.handlers, a)
	return a
}

func (a *action) Once(target int) *action {
	a.latency = &onceR{target: target}
	a.factor = 0
	return a
}

func (a *action) Range(left, right int) *action {
	a.latency = &rangeR{left: left, right: right}
	return a
}

func (a *action) Repeat(threshold int) *action {
	a.latency = &repeatR{threshold: threshold}
	return a
}

func (a *action) Stack(perStack int, maxStacks ...int) *action {
	limit := -1
	if len(maxStacks) > 0 {
		limit = maxStacks[0]
	}
	a.latency = &stackR{times: perStack, max: limit}
	a.factor = 0 // 从0开始叠加
	return a
}

func (a *action) On(e Event) *action {
	if a.Hook == nil {
		a.Hook = &Hook{event: e}
		return a
	}
	tail := a.Hook
	for ; tail.next != nil; tail = tail.next {
	}
	tail.next = &Hook{event: e}
	return a
}

func (a *action) AddCall(name string, call func(*Fight)) {
	a.name = name
	a.calls = append(a.calls, call)
}

func (a *action) SelfCall(name string, call func(*action, *Fight)) {
	target := func(fight *Fight) {
		call(a, fight)
	}
	a.name = name
	a.calls = append(a.calls, target)
}

func (a *action) TraceTrigger(name string) {
	a.name = name
	a.calls = append(a.calls, func(fight *Fight) {})
}
